#include "image_processing.h"
#include "jpeg_decoder.h"
#include "esp_log.h"
#include "esp_check.h"
#include <string.h>
#include "freertos/FreeRTOS.h"

#include <math.h>
#include "sdkconfig.h"

uint16_t *pixels;

extern const uint8_t image_jpg_start[] asm("_binary_image_jpg_start");
extern const uint8_t image_jpg_end[] asm("_binary_image_jpg_end");

const char *TAG = "ImageDec";

esp_err_t decode_image(uint16_t **pixels)
{
    *pixels = NULL;
    esp_err_t ret = ESP_OK;

    //Alocate pixel memory. Each line is an array of IMAGE_W 16-bit pixels; the `*pixels` array itself contains pointers to these lines.
    *pixels = calloc(IMAGE_H * IMAGE_W, sizeof(uint16_t));
    ESP_GOTO_ON_FALSE((*pixels), ESP_ERR_NO_MEM, err, TAG, "Error allocating memory for lines");

    //JPEG decode config
    esp_jpeg_image_cfg_t jpeg_cfg = {
        .indata = (uint8_t *)image_jpg_start,
        .indata_size = image_jpg_end - image_jpg_start,
        .outbuf = (uint8_t*)(*pixels),
        .outbuf_size = IMAGE_W * IMAGE_H * sizeof(uint16_t),
        .out_format = JPEG_IMAGE_FORMAT_RGB565,
        .out_scale = JPEG_IMAGE_SCALE_0,
        .flags = {
            .swap_color_bytes = 1,
        }
    };

    //JPEG decode
    esp_jpeg_image_output_t outimg;
    esp_jpeg_decode(&jpeg_cfg, &outimg);

    ESP_LOGI(TAG, "JPEG image decoded! Size of the decoded image is: %dpx x %dpx", outimg.width, outimg.height);

    return ret;
err:
    //Something went wrong! Exit cleanly, de-allocating everything we allocated.
    if (*pixels != NULL) {
        free(*pixels);
    }
    return ret;
}

static inline uint16_t get_bgnd_pixel(int x, int y)
{
    //Get color of the pixel on x,y coords
    return (uint16_t) * (pixels + (y * IMAGE_W) + x);
}

uint16_t get_campic_pixel(uint16_t *fbs,int x, int y)
{
    //Get color of the pixel on x,y coords
    return (uint16_t) * (fbs + (y * IMAGE_W) + x);
}

static int prev_frame = -1;

static int8_t xofs[240], yofs[240];
static int8_t xcomp[240], ycomp[240];

void pretty_effect_calc_lines(uint16_t *dest, int line, int frame, int linect)
{
    if (frame != prev_frame) {
        //We need to calculate a new set of offset coefficients. Take some random sines as offsets to make everything
        //look pretty and fluid-y.
        for (int x = 0; x < 240; x++) {
            xofs[x] = sin(frame * 0.15 + x * 0.06) * 4;
        }
        for (int y = 0; y < 240; y++) {
            yofs[y] = sin(frame * 0.1 + y * 0.05) * 4;
        }
        for (int x = 0; x < 240; x++) {
            xcomp[x] = sin(frame * 0.11 + x * 0.12) * 4;
        }
        for (int y = 0; y < 240; y++) {
            ycomp[y] = sin(frame * 0.07 + y * 0.15) * 4;
        }
        prev_frame = frame;
    }
    for (int y = line; y < line + linect; y++) {
        for (int x = 0; x < 240; x++) {
            *dest++ = get_bgnd_pixel(x + yofs[y] + xcomp[x], y + xofs[x] + ycomp[y]);
        }
    }
}

void show_565_pictures(uint16_t *dest, int line, int frame, int linect)
{
    if (frame != prev_frame) {
        prev_frame = frame;
    }
    for (int y = line; y < line + linect; y++) {
        for (int x = 0; x < 240; x++) {
            *dest++ = get_bgnd_pixel(x, y);
        }
    }
}
void show_565_campic(uint16_t *fbs,uint16_t *dest, int line, int frame, int linect)
{
    if (frame != prev_frame) {
        prev_frame = frame;
    }
    for (int y = line; y < line + linect; y++) {
        for (int x = 0; x < 240; x++) {
            *dest++ = get_campic_pixel(fbs,x, y);
        }
    }
}

esp_err_t pretty_effect_init(void)
{
    return decode_image(&pixels);
}

